
#include "sock.hpp"
#include <functional>

static const int defaultport=8080;
static const int defaultfd=-1;
static const int fdnum=sizeof(fd_set)*8;

using func_t=std::function<std::string (const std::string&)>;

class SelectServer{

    public:
        SelectServer(func_t func,int port=defaultport):_port(port),_listsock(-1),_fdarray(nullptr),_func(func){}

        void initServer(){
            _listsock=sock::Socket();
            sock::Bind(_listsock,_port);    
            sock::Listen(_listsock);
            _fdarray=new int[fdnum];
            for(int i=0;i<fdnum;++i){
                _fdarray[i]=defaultfd;
            }
            _fdarray[0]=_listsock;
        }

        void Print(){
            for(int i=0;i<fdnum;++i){
                if(_fdarray[i]!=defaultfd){
                    std::cout<<_fdarray[i]<<" ";
                }
            }
            std::cout<<endl;
        }

        void Accepter(){
            std::string clientip;
            uint16_t clientport=0;
            int sock=sock::Accept(_listsock,&clientip,&clientport);
            if(sock<0){
                return;
            }
            logMessage(NORMAL, "accept success [%s:%d]", clientip.c_str(), clientport);
            // sock我们能直接recv/read 吗？不能，整个代码，只有select有资格检测事件是否就绪
            // 将新的sock 托管给select！
            // 将新的sock托管给select的本质，其实就是将sock，添加到fdarray数组中即可！
            int i=0;
            for(;i<fdnum;++i){
                if(_fdarray[i]!=defaultfd) continue;
                else break;
            }
            if(i==fdnum){
                logMessage(WARNING,"server if full,please wait");
                close(sock);
            }else{
                _fdarray[i]=sock;
            }
            Print();
        }

        void Recver(int sock,int pos){
            // 1. 读取request
            // 这样读取是有问题的！--现在姑且这样处理
            char buff[1024];
            ssize_t s=recv(sock,buff,sizeof(buff)-1,0);//在这里进行读取的时候，是不会被阻塞的
            if(s>0){
                buff[s]=0;
                logMessage(NORMAL,"client# %s",buff);
            }else if(s==0){
                close(sock);
                _fdarray[pos]=defaultfd;
                logMessage(NORMAL,"client quit");
                return;
            }else{
                close(sock);
                _fdarray[pos]=defaultfd;
                logMessage(ERROR,"client quit: %s",strerror(errno));
                return;
            }
            //2. 处理request
            std::string respone=_func(buff);
            //3.返回response
            //这里这样处理也是有bug的
            write(sock,respone.c_str(),respone.size());
        }

       // 1. handler event rfds 中，不仅仅是有一个fd是就绪的，可能存在多个
        // 2. 我们的select目前只处理了read事件
        void HandlerEvent(fd_set& rfds){
            for(int i=0;i<fdnum;++i){
                //过滤非法的fd
                if(_fdarray[i]==defaultfd) continue;
                //正常的fd
                if(FD_ISSET(_fdarray[i],&rfds) && _fdarray[i]==_listsock)
                    Accepter();
                else if(FD_ISSET(_fdarray[i],&rfds))
                    Recver(_fdarray[i],i);
                else {}
                    //....
            }
        }

        void start(){
            for(;;){
                fd_set rfds;
                FD_ZERO(&rfds);
                int maxfd=_fdarray[0];

                for(int i=0;i<fdnum;++i){
                    if(_fdarray[i]==defaultfd) continue;
                    FD_SET(_fdarray[i],&rfds);//将合法的fd添加到读文件描述符集中
                    if(maxfd<_fdarray[i]) maxfd=_fdarray[i];// 更新所有fd中最大的fd
                }
                  // 一般而言，要是用select，需要程序员自己维护一个保存所有合法fd的数组！
                int n=select(maxfd+1,&rfds,nullptr,nullptr,nullptr);
                switch(n){
                    case 0:
                        logMessage(NORMAL,"timeout....");
                        break;
                    case -1:
                        logMessage(WARNING,"select error,code %d ,err string %s",errno,strerror(errno));
                        break;
                    default:
                        logMessage(NORMAL,"get a new link...");
                        HandlerEvent(rfds);
                        break;
                }

            }
        }

        ~SelectServer(){
            if(_listsock>0)
                close(_listsock);
        }
    private:
        int _port;
        int _listsock;
        int* _fdarray;
        func_t _func;
};


